package core;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

/**
 * Monitors performance and prints all monitored parts of the program.
 * Black graph is 1/100 of the green graph.
 * Numbers indicate the biggest spike of each iteration in milliseconds
 * 
 * @author Anton
 *
 */

public class PerformanceMonitor {
	
	private static final int resolution = 100;
	private static final int maxAttributes = 10;

	private static PerformanceMonitor[] monitors = new PerformanceMonitor[maxAttributes];
	private static PerformanceMonitor loopMonitor = new PerformanceMonitor("Loop");
	private static int indexOfEmpty = 0;
	private static int searchIndex = 0;  // next check is usually the same or next element, goes faster saving the index.
	
	
	private String name;
	private long[] recentTimes = new long[resolution];
	private long startTime, totalTime=0, maxTime=0;
	private int recentIndex = 0;
	
	//LPS variables
	private static int lps, lpscounter;
	private static long logicLastSecondStart;
	
	//FPS variables
	private static int fps, fpscounter;
	private static long lastSecondStart;
	
	private PerformanceMonitor(String n){
		name = n;
	}
	public static void startCheck(String attributeName){
		for(int i=0; i<maxAttributes; i++){
			if(monitors[searchIndex] != null && monitors[searchIndex].name.equalsIgnoreCase(attributeName)){
				monitors[searchIndex].startCheck();
				return;
			}
			searchIndex = (searchIndex+1)%maxAttributes;
		}
		
		// no element found:
		monitors[indexOfEmpty] = new PerformanceMonitor(attributeName);
		monitors[indexOfEmpty].startCheck();
		indexOfEmpty++;
	}
	public static void stopCheck(String attributeName){
		for(int i=0; i<maxAttributes; i++){
			if(monitors[searchIndex] != null && monitors[searchIndex].name.equalsIgnoreCase(attributeName)){
				monitors[searchIndex].stopCheck();
				return;
			}
			searchIndex = (searchIndex+1)%maxAttributes;
		}
	}
	private void startCheck(){
		startTime = System.nanoTime();
	}
	private void stopCheck(){
		recentTimes[recentIndex] = System.nanoTime() - startTime;
		recentIndex++;
		if(recentIndex == resolution){
			totalTime=0;
			maxTime=0;
			for(long i : recentTimes){
				totalTime += i/resolution;
				if(i > maxTime)
					maxTime = i;
			}
			recentIndex=0;
		}
	}
	public static void finishLoop(){
		loopMonitor.stopCheck();
		loopMonitor.startCheck();
		
		lpscounter++;
		if(logicLastSecondStart < System.nanoTime() - 1000000000){
			logicLastSecondStart = System.nanoTime();
			lps=lpscounter;
			lpscounter=0;
		}
	}
	public static void finishFrame(){
		fpscounter++;
		if(lastSecondStart < System.nanoTime() - 1000000000){
			lastSecondStart = System.nanoTime();
			fps=fpscounter;
			fpscounter=0;
		}
	}
	
	public static void paint(Graphics g, int x, int y){
		Graphics2D g2d = (Graphics2D)g;
		g2d.setStroke(new BasicStroke(1));
		
		g.setFont(Constants.defaultFont);
		
		for(PerformanceMonitor m : monitors){
			if(m != null){
				g.setColor(Color.white);
				g.fillRect(x, y, 200, 15);
				if(loopMonitor.totalTime != 0){
					g.setColor(Color.red);
					int lengthOfRed = (int)(100*m.totalTime / loopMonitor.totalTime);
					g.fillRect(x+200-lengthOfRed, y, lengthOfRed, 15);
					lengthOfRed = (int)(100*(m.maxTime) / loopMonitor.totalTime)*2;

					int dx = 100*resolution;
					int incx = 100;
					int thisY, lastY=y;
					g.setColor(Color.gray);
					
					for(long i : m.recentTimes){
						if(m.totalTime != 0)
							thisY=(int)(8*i/m.totalTime)-1;
						else
							thisY=0;
						g.setColor(Color.green);
						g.drawLine(x+dx/resolution, y+14-lastY, x+(dx+incx)/resolution, y+14-thisY);
						g.setColor(Color.black);
						g.drawLine(x+dx/resolution, y+14-lastY/100, x+(dx+incx)/resolution, y+14-thisY/100);
						lastY=thisY;
						dx=dx+incx;
					}
					g.setColor(Color.gray);
					g.drawLine(x+100, y, x+100, y+15);
				}
				g.setColor(Color.black);
				g.drawString(m.name + ": " + m.maxTime/1000000, x+2, y+12);
				
				y+=15;
			}
		}
		g.setColor(Color.CYAN);
		g.drawString("FPS: " + fps+"  Speed: " + lps +"%",  x+2, y+12);
	}
	
}
